import os
import sys
import zmq
import traceback
import imp
from zmq.utils import jsonapi
from zmq.core import poll

import ioloop
import znode
from handlers.zmq import ZMQHandler, InvalidZMQObject

import logging
from basedaemon import BaseDaemon


class AppServer(BaseDaemon):
    """docstring for AppServer"""

    def __init__(self, pidfile, zmq_host,
                 zmq_port, zmq_transport,
                 zmq_debug, app_settings_file,
                 **kwargs):
        super(AppServer, self).__init__(pidfile, **kwargs)

        logging.info(("AppServer::__init__("
                " pidfile:%s, zmq_host:%s, zmq_port:%s,"
                 " zmq_transport:%s, app_settings_file:%s")
                % (pidfile, zmq_host, zmq_port, zmq_transport,
                     app_settings_file))

        self.admin_node = None
        self.transport = zmq_transport
        self.host = zmq_host
        self.port = zmq_port
        self.debug = zmq_debug
        self.settings_file = app_settings_file

        self.context = None
        #self.socket = None
        self.application = None

        self.ioloop = ioloop.IOLoop.instance()

        self._nodes = {}
    #__init__()

    def run(self):
        """docstring for run"""

        # import settings and get the application callable
        logging.debug("Import the dmq application file:%s" %
                (self.settings_file))
        try:
            if not os.path.exists(self.settings_file):
                raise Exception("The dmq application file:%s does not exist" %
                                (self.settings_file))
            django_dmq = imp.load_source('django_dmq', self.settings_file)
            self.application = django_dmq.application
        except Exception as e:
            logging.error("Unable to import dmq application file:%s\n%s"
                % (self.settings_file, e))
            raise Exception("Unable to import dmq application file:%s\n%s"
                % (self.settings_file, e))

        # It's expected that the application settings file setup the
        # Django settings variable, so now we can import from Django
        from django.core.serializers.json import DjangoJSONEncoder

        environ = dict(os.environ.items())
        environ['DMQ_APPLICATION_SETTINGS_FILE'] = self.settings_file
        environ['SERVER_PORT'] = self.port

        self.admin_node = znode.ZNode(
            self.application,
            transport=self.transport,
            endpoint=self.host,
            port=self.port,
        )

        self.ioloop.add_node(self.admin_node)
        poller = poll.Poller()
        poller.register(socket, zmq.POLLIN | zmq.POLLOUT)

        orig_req = ""
        resp = ""
        while self.keep_running:
            try:
                sockets = dict(poller.poll(1))
                if socket in sockets:
                    if socket == socket:
                        status = sockets[socket]
                        if status == zmq.POLLIN:
                            orig_req = socket.recv()
                            logging.debug('AppServer::run() got orig_req:%s' %
                                    orig_req)
                            # We do the the heavy lifting in Django the extra
                            # ZMQ* Django classes we add.
                            # So this is pretty simple, call Django to process
                            # the request
                            resp = self.application(environ, orig_req)
                        elif status == zmq.POLLOUT:
                            # Responde with Django's reply.
                            # Simply requesting the response
                            # objects string will
                            # get us its JSON encoding
                            socket.send(str(resp))

            except Exception as e:
                if self.keep_running:
                    logging.error('AppServer::run() Got exception:%s\n%s' %
                            (e, traceback.format_exc()))
                    if not socket.closed and status == zmq.POLLOUT:
                        logging.error(('AppServer::run() trying to send'
                                 ' back an error message'))
                        msg = {'success': False, 'error_str': str(e),
                               'orig_request': orig_req}
                        socket.send(jsonapi.dumps(msg, cls=DjangoJSONEncoder))

    #run()
#AppServer
